//dep
window.ServerProxy = new function() {
	
	var ef = IOFactory.createEncodingFacade();
	var inc = 0;
	var err = 0;
	
	var errtag = null;
	var errxml = new XMLHttpRequest();
	
	this.listServices = function(k) {
		var inv = new TITTInvoker(["titt"]);
		inv.dynCall("list", [], k);
	}
	
	this.gensym = function(k) {
		var inv = new TITTInvoker(["titt"]);
		inv.dynCall("gensym", [], k);
	}
	
	this.register = function(o, tokens, k) {
		this.registerWithLink(o, tokens, null, k);
	}
	
	this.registerWithLink = function(o, tokens, lnk, k) {
		var arr = new Array();
		arr[0] = "titt";
		for(var i = 0; i < tokens.length; i++)
			arr[i+1] = tokens[i];
		
		var inv = new TITTInvoker(arr);
		var internal = new TITTInternal();
		
		var regInterface = new TypedObject(Types.toArray(Types.toArray(Types.STRING)), internal.getInterface(o));
		
		var args = [regInterface];
		if(lnk)
			args = [regInterface, new TypedObject(Types.STRING, lnk)];
		inv.call("register", args, function(ret){ k(ret.getObject()); });
	}
	
	this.detectErrors = function(serviceID, k) {
		ServiceUtil.init(function() {
			doDetectErrors(serviceID,k);
		})
	}
	
	function doDetectErrors(serviceID, k) {
		/*		var ts = IOFactory.createTITTSocket();
		
		ts.getHeadWriter().writeHead(createTITTCallHead(TITTValues.GET, "error", [serviceID]));
		ts.getOutputStream().flush(function(){
			k();
			ts.close();
			delete ts;
		});*/
		//save one connection here :)
		
		var loc = ServiceUtil.generateDomain()+"/titt/error?string=" + serviceID;
		
		function detect() {
			if(errxml) {
				try {
					errxml.abort();
					errxml.open("GET", loc, true);
					errxml.onreadystatechange = function(){}
					errxml.send(null);
				}
				catch(err) {
					errxml = null;
					detect();
				}
			}
			else {
				if(errtag)
					document.body.removeChild(errtag);
				
				errtag = document.createElement("script");
				errtag.src = loc
				document.body.appendChild(errtag);
			}
		}
		detect();

	}
	
	
	this.syncResponseContent = function(stat, ret, packageID, k) {
		var socket = this.sync(packageID)

		function innerk(){
			k();
			socket.close();
			delete socket;
		}
		
		if(ret) {
			var rw = new ResponseWriter(socket, ef, new ResponseHeadInit(stat, HeadFactory.EMPTY));
			rw.writeValues([ret], innerk);
		}	
		else {
			socket.getHeadWriter().writeHead(new ResponseHeadInit(stat, HeadFactory.EMPTY));
			socket.getOutputStream().flush(innerk);
		}
	}
		
	this.syncResponse = function(stat, packageID, k) {
		this.syncResponseContent(stat, null, packageID, k);
	}
	
	this.sync = function(packageID) {
		var socket = IOFactory.createTITTSocket();
		socket.getHeadWriter().writeHead(createTITTCallHead(TITTValues.POST, "sync", [packageID]));
		return socket;
	}
	
	this.unregister = function(serviceID, forgiving, k) {
		var socket = IOFactory.createTITTSocket();
		socket.getHeadWriter().writeHead(createTITTCallHead(TITTValues.GET, "unregister", [serviceID, forgiving]));
		socket.getOutputStream().flush(function() {
			socket.getHeadReader().readHead();
			k();
			socket.close();
			delete socket;
		});
	}
	
	this.withdraw = function(serviceID, k) {
		var sp = this;
		var socket = IOFactory.createTITTSocket();
		
		socket.getHeadWriter().writeHead(createTITTCallHead(TITTValues.GET, "withdraw", [serviceID, inc++]));
		socket.getOutputStream().flush(function() {
			try {
				var resp = new ResponseHead(socket.getHeadReader().readHead());
				err = 0;
				if (resp.getStatusCode() != 200) {					
					k(null);
				}
				else {
					var pack = new ServicePackage(resp.getHeader("E-Tag").getValue(), socket.getHeadReader().readHead(), socket);
					k(pack);
				}
			}
			catch(errmsg) {
				if(err > 1) {
					k(null);
					return;
				}
				err++;
				//try again...
				sp.withdraw(serviceID, k);
			}
			socket.close();
			delete sp; delete socket; 
		});
		
	}
	
	function createTITTCallHead(method, methodName, args) {
		var tos = new Array();
		for(var i = 0; i < args.length; i++)
			tos[i] = new TypedObject(new TypeFromObject(args[i]), args[i]);
	
		var req = new RequestHeadInit(method, "/titt/", HeadFactory.EMPTY);
		return new MethodHeadInit(methodName, tos, [], req);
	}
}